package com.jlpay.open.jlpay.sdk.java.service;

import com.jlpay.open.jlpay.sdk.java.config.NotifyConfig;
import com.jlpay.open.jlpay.sdk.java.enums.SignType;
import com.jlpay.open.jlpay.sdk.java.exception.SignVerifyException;
import com.jlpay.open.jlpay.sdk.java.model.notify.NotifyParam;
import com.jlpay.open.jlpay.sdk.java.sign.SignVerifier;
import com.jlpay.open.jlpay.sdk.java.utils.json.JsonUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import java.util.Objects;

import static java.util.Objects.requireNonNull;

/**
 * 通知解析
 *
 * @author xuexiaoya
 * @version 2024/03/14
 **/
public class JlpayNotifyParseService {

    private static final Logger LOGGER = LoggerFactory.getLogger(JlpayNotifyParseService.class);


    private final NotifyConfig config;


    public JlpayNotifyParseService(NotifyConfig config) {
        this.config = config;
    }

    public <T> T parse(NotifyParam requestParam, Class<T> decryptObjectClass) {
        validateRequest(requestParam);
        return getObject(requestParam, requireNonNull(decryptObjectClass));
    }

    private <T> T getObject(NotifyParam requestParam, Class<T> objectClass) {
        return JsonUtils.parseObject(requestParam.getBody(), objectClass);
    }

    /**
     * 验证签名
     *
     * @param notifyParam
     */
    private void validateRequest(NotifyParam notifyParam) {
        if (notifyParam == null) {
            throw new SignVerifyException("verify signature failed, notifyParam is null");
        }
        if (notifyParam.getAlg() == null) {
            throw new SignVerifyException("verify signature failed, signType is empty");
        }
        if (notifyParam.getNonce() == null) {
            throw new SignVerifyException("verify signature failed, nonce is empty");
        }
        if (notifyParam.getTimestamp() == null) {
            throw new SignVerifyException("verify signature failed, timestamp is empty");
        }
        if (notifyParam.getBody() == null) {
            throw new SignVerifyException("verify signature failed, body is empty");
        }
        if (notifyParam.getSign() == null) {
            throw new SignVerifyException("verify signature failed, sign is empty");
        }
        SignType signType = SignType.getByCode(notifyParam.getAlg());
        if (signType == null) {
            throw new SignVerifyException("verify signature failed, unsupported algorithm ");
        }

        SignVerifier signVerifier = config.createSignerVerifier();
        LOGGER.debug("verify signature: {}", notifyParam.getSign());
        String signContent = notifyParam.buildSignContent();
        LOGGER.debug("verify content: {}", signContent);
        if (!signVerifier.verify(signContent, notifyParam.getSign(), signType.getCode())) {
            throw new SignVerifyException("verify signature failed");
        }
    }

    public static class Builder {


        private NotifyConfig config;

        public JlpayNotifyParseService.Builder config(NotifyConfig config) {
            this.config = config;
            return this;
        }


        public JlpayNotifyParseService build() {
            Objects.requireNonNull(config, "config is required");
            return new JlpayNotifyParseService(config);
        }
    }


}
